package net.laenzlinger.decision.service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import net.laenzlinger.decision.domain.RuleBase;
import net.laenzlinger.decision.service.container.Action;
import net.laenzlinger.decision.service.container.InputParameters;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.DecisionTableConfiguration;
import org.drools.builder.DecisionTableInputType;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.Resource;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatelessKnowledgeSession;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

@Service
public class RuleEngineService {

	private static final Logger LOGGER = Logger.getLogger(RuleEngineService.class.getName());

	private static final String NAME_RESULTING_ACTIONS = "actions";
	private final Map<Long, KnowledgeBaseEntry> knowledgeBases = new ConcurrentHashMap<Long, KnowledgeBaseEntry>();

	private KnowledgeBase createKnowledgeBase(byte[] xls) throws KnowledgeBuilderException {
		DecisionTableConfiguration decisionTableConfiguration = KnowledgeBuilderFactory.newDecisionTableConfiguration();
		decisionTableConfiguration.setInputType(DecisionTableInputType.XLS);
		KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
		Resource resource = ResourceFactory.newByteArrayResource(xls);
		knowledgeBuilder.add(resource, ResourceType.DTABLE, decisionTableConfiguration);

		if (knowledgeBuilder.hasErrors()) {
			throw new KnowledgeBuilderException(knowledgeBuilder.getErrors());
		}
		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
		kbase.addKnowledgePackages(knowledgeBuilder.getKnowledgePackages());
		return kbase;
	}

	public List<Action> execute(InputParameters parameters, RuleBase rules) throws KnowledgeBuilderException {

		List<Action> resultingActions = Lists.newArrayList();
		StatelessKnowledgeSession ksession = getKnowledgeBase(rules).newStatelessKnowledgeSession();
		KnowledgeRuntimeLoggerFactory.newConsoleLogger(ksession);
		ksession.setGlobal(NAME_RESULTING_ACTIONS, resultingActions);
		ksession.execute(parameters);

		return resultingActions;

	}

	private KnowledgeBase getKnowledgeBase(RuleBase rules) throws KnowledgeBuilderException {
		Long id = rules.getId();
		Integer version = rules.getVersion();
		String name = rules.getName();
		if (knowledgeBases.containsKey(id) && knowledgeBases.get(id).getVersion().equals(version)) {
			LOGGER.info("get knowledge base [" + name + "] from cache");
			KnowledgeBaseEntry knowledgeBaseEntry = knowledgeBases.get(id);
			return knowledgeBaseEntry.getKnowledgeBase();
		} else {
			LOGGER.info("create knowledge base [" + name + "]");
			final KnowledgeBase knowledgeBase = createKnowledgeBase(rules.getContent());
			knowledgeBases.put(id, new KnowledgeBaseEntry(version, knowledgeBase));
			return knowledgeBase;
		}
	}
}
